namespace FilesBackup;

using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;

using JoinBox.Basal;
using static JoinBox.Basal.FileHelper;
using static JoinBox.Basal.IntranetPath;
using Path = System.IO.Path;

public partial class FilesBackupForm : Form
{
    #region 成员
#if HongZa
    private const string _pcNameMostly = "A2"; // 局域网访问名称
    private const string _proName = "饰施图";   // 局域网访问的共享文件夹
#elif RuiZa
    private const string _pcNameMostly = "HZR";// 局域网访问主机名称
    private const string _proName = "施工图";   // 局域网访问的共享文件夹
#endif
    public const string _SharedFoldersA = "中转站";
    public const string _SharedFolders = @"\" + _SharedFoldersA;

    string? _exePath;
    /// <summary>
    /// 获取当前exe完整路径
    /// </summary>
    public string ExePath
    {
        get
        {
            if (_exePath == null)
            {
                // 获取exe完整路径,若是网络驱动器,就转换,本地就原本
                _exePath = GetUNCPath(Process.GetCurrentProcess().MainModule.FileName);
                // 可以获得不带文件名的路径
                _exePath = Path.GetDirectoryName(_exePath);
            }
            return _exePath;
        }
    }

    /// <summary>
    /// 点击计数,用于重新初始化
    /// </summary>
    static int CheckedListBox1Counter = 0;
    /// <summary>
    /// 暂停修改checkedListBox1
    /// </summary>
    bool on_off = false;
    /// <summary>
    /// ping类
    /// </summary>
    PingPingPing _ping;
    #endregion

    #region 构造
    public FilesBackupForm()
    {
        InitializeComponent();
        // TopMost = true;// 置顶窗体
        // FormBorderStyle = FormBorderStyle.FixedSingle;// 设置边框为不可调节
        StartPosition = FormStartPosition.CenterScreen;// 在当前屏幕中央

        checkedListBox1.HorizontalScrollbar = true;// 显示垂直滚动条
        checkedListBox1.ScrollAlwaysVisible = true;// 显示水平滚动条
        checkedListBox1.CheckOnClick = true;// 按一下就打钩

        _ping = new(_SharedFoldersA);
        Load += IntranetBackupDevice_Load;
    }

    private void IntranetBackupDevice_Load(object sender, EventArgs e)
    {
        try
        {
            var gios = new GetIpOrSegment();
            if (gios.NetworkSegment == null)
                throw new ArgumentException(nameof(gios.NetworkSegment));

            _ping.NetworkSegment = gios.NetworkSegment;
            textBox3.Text = gios.NetworkSegment;

            label6.Text = "默认主机:" + _pcNameMostly;
            button1.TabIndex = 0;

            var rs = Regex.Split(ExePath, "CAD阶段");
            if (rs.Length <= 1)
                rs = Regex.Split(ExePath, _proName); // 切割 "饰施图"  获取项目名

            if (rs.Length > 1)
            {
                // 获取项目名
                var path = rs[0]?.Trim('\\');
                path = Path.GetDirectoryName(path);
                int last = path.LastIndexOf('\\');
                if (last == -1)
                    throw new ArgumentNullException("项目名出错:" + rs[0]);
                var projectName = path.Substring(last, path.Length - last);

                textBox2.Text = projectName;
                label7.Text = "警告:无";
            }
            else
            {
                textBox2.Text = Path.GetFileName(ExePath);// 获取文件名
                label7.Text = string.Format("警告:当前备份器exe不在 {0} 内,将采用以上对话框信息备份.", _proName);
            }

            var beifennian = StringHelper.GetFlie4Number(textBox2.Text);
            if (beifennian == "0")// 年份确定
            {
                DateTime currentTime = DateTime.Now;
                textBox4.Text = currentTime.Year.ToString();
            }
            else
            {
                textBox4.Text = beifennian;
            }

            {
                // 执行死循环修改的
                // 创建线程 Invoke方法是同步的方法，所以执行过程是有先后顺序的，所以就不会出现那个异常了
                Thread newThread = new(RunAddPcIp)
                {
                    IsBackground = true
                };
                newThread.Start();
            }

            {
                ThreadPool.GetMaxThreads(out int max, out int maxIo);
                ThreadPool.GetMinThreads(out int min, out int minIo);

                int ipNumbers = _ping.IpNumber + 1;
                if (max - ipNumbers > 0)
                    max = ipNumbers;
                if (maxIo - ipNumbers > 0)
                    maxIo = ipNumbers;
                if (min - ipNumbers < 0)
                    min = ipNumbers;
                if (minIo - ipNumbers < 0)
                    minIo = ipNumbers;

                // 启动线程池
                bool maxbool = ThreadPool.SetMaxThreads(max, maxIo);
                bool minbool = ThreadPool.SetMinThreads(min, minIo);
                if (maxbool && minbool)
                {
                    // 开始就执行遍历局域网
                    Button4_Click(null!, null!);
                    // label7.Text = string.Format("注明:线程数设置{0},{1},{2},{3}", max, maxIo, min, minIo);
                }
                else
                {
                    label7.Text = "警告:线程数设置失败";
                }
            }
        }
        catch (Exception eee)
        {
            label7.Text = eee.Message;
        }
    }
    #endregion

    /// <summary>
    /// 点击备份
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Button1_Click(object sender, EventArgs e)
    {
        string dPath = textBox1.Text;
        if (dPath == "")
        {
            label7.ForeColor = System.Drawing.Color.Red;
            label7.Text = "警告:备份路径为空!";
            return;
        }

        if (Directory.Exists(dPath))// 防止第二次点击备份
        {
            label7.ForeColor = Color.Blue;
            label7.Text = "警告:路径已经存在,请更换路径!(是否重复备份了?)";
        }
        else
        {
            label7.Text = "警告:正在备份......";
            // 新建线程执行复制
            var thread = new Thread(RunCopyFile);
            thread.Start();
        }
    }


    /// <summary>
    /// 设置线程,运行copy文件
    /// </summary>
    public void RunCopyFile()
    {
        if (ExePath == null)
            throw new ArgumentNullException(nameof(ExePath));

        var errorMsg = new StringBuilder();

        // 拷贝计算文件大小,控制进度条
        var max = GetAllFileLength(ExePath, errorMsg);
        if (max == 0)
        {
            label7.Text = "警告:无内容备份";
            return;
        }

        Invoke((EventHandler)delegate
        {
            progressBar1.Value = 0;     // 进度条当前位置为0
            progressBar1.Minimum = 0;   // 进度条的最小值为0
            progressBar1.Maximum = (int)max; // 进度条的最大值

            try
            {
                // 复制文件
                Copy(ExePath, textBox1.Text, (prog) => {
                    progressBar1.Value += (int)prog;
                }, errorMsg);

                label7.ForeColor = Color.MediumSeaGreen;
                label7.Text = "警告:备份成功!";
                button5.TabIndex = 0;// 设置焦点到打开文件夹
            }
            catch (Exception e)
            {
                // 实现回滚效果
                DelPath(textBox1.Text, (prog) => {
                    progressBar1.Value += (int)prog;
                }, errorMsg);

                label7.ForeColor = Color.Blue;
                label7.Text = "警告:备份不成功,已执行回滚,请再尝试!" + e.Message;
            }
            textBox5.AppendText(errorMsg.ToString());
        });
    }

    /// <summary>
    /// Esc键退出
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyValue == 27) // Esc键
            Close();
    }

    /// <summary>
    /// 窗体将比其内的控件优先获得键盘事件的激活权
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Form1_Load(object sender, EventArgs e)
    {
        KeyPreview = true;
    }

    /// <summary>
    /// 开始ping 遍历局域网
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Button4_Click(object sender, EventArgs e)
    {
        // 如果用多线程调用的话,会出现多个pingEnt和qiyongEnt值,对加入表造成错误例如多个A2
        try
        {
            // 暂停加表,清空表,初始化
            on_off = false;
            {
                _ping.pingEnt++;
                _ping.qiyongEnt++;
                _ping.NetworkSegment = textBox3.Text;

                CheckedListBox1Counter = 0;
                for (int i = 0; i < checkedListBox1.Items.Count; i++)
                    checkedListBox1.Items.Clear();

                _ping = new(_SharedFoldersA);
            }
            on_off = true; // 继续加入表中

            for (int i = 0; i < _ping.IpNumber; i++)// 生成255个线程
            {
                ThreadPool.QueueUserWorkItem(
                     new WaitCallback(_ping.PingIP),
                     new int[] { i, _ping.qiyongEnt });
            }
        }
        catch
        {
            label7.Text = "警告:RunPing出错";
        }
    }

    /// <summary>
    /// 通过委托实现死循环修改面板
    /// </summary>
    ///  https://blog.csdn.net/htiannuo/article/details/52229695
    public void RunAddPcIp()
    {
        StringBuilder space;
        HostInfo conameN;

        while (on_off)
        {
            lock (_ping.ComputerNames)
            {
                if (CheckedListBox1Counter >= _ping.ComputerNames.Count)
                {
                    Thread.Sleep(50);
                    continue;
                }
                conameN = _ping.ComputerNames[CheckedListBox1Counter];
            }

            string hostName = conameN.HostName;
            if (hostName != "" && conameN.HostIP != "")// 锁了就应该不会出现这样的问题了
            {
                hostName = hostName.ToUpper();
                Invoke((EventHandler)delegate
                {
                    // ip可能为名称,ip长度 255.255.255.255  15长+5个空格=20
                    int bukongge = 20 - hostName.Length;
                    space = new StringBuilder();
                    for (int i = 0; i < bukongge; i++)
                        space.Append(" ");

                    checkedListBox1.Items.Add(
                        hostName + space + conameN.HostIP + " \t" + conameN.Remarks);

                    if (hostName == _pcNameMostly)
                    {
                        // 选择默认主机
                        checkedListBox1.SetItemCheckState(CheckedListBox1Counter, CheckState.Checked);// 打钩
                        checkedListBox1.SelectedIndex = CheckedListBox1Counter;// 焦点项
                    }
                });
            }
            CheckedListBox1Counter++;
            Thread.Sleep(400);
        }
    }

    /// <summary>
    /// 打开文件夹
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Button5_Click(object sender, EventArgs e)
    {
        if (Directory.Exists(textBox1.Text)) // 若路径存在
        {
            Process.Start("explorer.exe", textBox1.Text);
        }
        else
        {
            label7.ForeColor = Color.Red;
            label7.Text = "警告:备份路径为空!请点击备份再点我~";
        }
    }

    /// <summary>
    /// 弄成单选
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void CheckedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
    {
        // 取消选中就不用进行以下操作
        if (e.CurrentValue == CheckState.Checked)
            return;

        // 将所有选项设为不选中
        var listbox = (CheckedListBox)sender;
        for (int i = 0; i < listbox.Items.Count; i++)
            listbox.SetItemChecked(i, false);

        e.NewValue = CheckState.Checked;// 刷新
    }

    private static string patha = "";
    private static string pathTime = "";

    /// <summary>
    /// CheckedListBox1选择事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void CheckedListBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
        // if (!buchufagenggai)用了的话会无法直接出现在 textBox1.Text
        //     return;

        // 获取唯一选中项,修改textBox1路径
        for (int j = 0; j < checkedListBox1.Items.Count; j++)
        {
            if (!checkedListBox1.GetItemChecked(j))
                continue;

            var conames = _ping.ComputerNames.ToArray();
            string time = StringHelper.GetTimeNoSeconds(out int miao);
            string pathb = @"\\" + conames[j].HostName + _SharedFolders;
            string pathc = @"\\" + conames[j].HostIP + _SharedFolders;

            for (int i = 0; true; i++)
            {
                bool existsPathb = Directory.Exists(pathb);
                if (!existsPathb)
                {
                    existsPathb = Directory.Exists(pathc);
                    patha = pathc;
                }
                else
                {
                    patha = pathb;
                }

                if (existsPathb) // 存在一级
                {
                    pathTime = time + (miao + i).ToString("#00");// 循环名称不加长
                    string path = ChangPath(textBox4.Text, textBox2.Text);
                    if (!Directory.Exists(path)) // 存在就循环
                    {
                        textBox1.Text = path;
                        break;
                    }
                }
                else
                {
                    MessageBox.Show(patha +
                        Environment.NewLine + "\n无法连接,没有开机?不存在机名?没有访问权限?",
                        "惊惊连盒",
                        MessageBoxButtons.OK);
                    break;
                }
            }
            break;
        }
    }

    // 关闭
    private void Button2_Click(object sender, EventArgs e)
    {
        Close();
    }

    // 作者信息
    private void Button3_Click(object sender, EventArgs e)
    {
        var jj = "www.cnblogs.com/JJBox";
        var dr = MessageBox.Show(
            "说明:本程序会在'备份器exe所在位置'进行备份" +
             Environment.NewLine + "此文件夹前将视为'项目文件夹': " + _proName +
             Environment.NewLine + "更换网段时候后需要重新ping" +
             Environment.NewLine + "深圳壹席设计事务所有限公司&东莞市罗道夫空间设计有限公司" +
             Environment.NewLine + "\n作者:刘启宏Liuqihong    企鹅:540762622" +
             Environment.NewLine + "博客: " + jj + " ('确定' 进入博客)"
            , "惊惊连盒",
            MessageBoxButtons.OKCancel);

        if (dr == DialogResult.OK)
            Process.Start(jj);
    }

    private void TextBox2_TextChanged(object sender, EventArgs e)
    {
        if (patha != "")// 防止初始化的时候就更改
            textBox1.Text = ChangPath(textBox4.Text, textBox2.Text);
    }

    /// <summary>
    /// 备份全路径
    /// </summary>
    /// <param name="year">备份年份</param>
    /// <param name="project">项目名</param>
    /// <returns></returns>
    private string ChangPath(string year, string project)
    {
        return patha + "\\" + year + "\\" + project + "\\" + _proName + "\\" + pathTime;
    }

    /// <summary>
    /// 打开当前exe所在文件夹
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Button6_Click(object sender, EventArgs e)
    {
        Process.Start(ExePath);
    }
}